package com.abcode.st.interceptor;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.validation.BindingResult;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartException;
import org.springframework.web.multipart.support.StandardMultipartHttpServletRequest;
import org.springframework.web.util.ContentCachingRequestWrapper;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.nio.charset.Charset;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

/**
 * 
 * @Description: 访问接口的参数以及返回结果的日志
 *
 */
@Component
@Aspect
public class ControllerAopInterceptor {
	/** 初始化日志打印 */
	public static final Logger log = LoggerFactory.getLogger("visitLog");

	//<editor-fold desc="异常切入点">
	@Pointcut("execution(public * com.abcode.st.exception.GlobalExceptionHandle.*(..))")
	public void controllerException() {
	}
	@Around("controllerException()")
	public Object aroundControllerException(ProceedingJoinPoint pjp) throws Throwable {
		// 定义返回参数
		Object result = null;
		HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();

		// 请求的URL
		String requestURL = request.getRequestURL().toString();
		String ip = getIpAddr(request);

		String paramStr = null;
		if (request != null && request instanceof ContentCachingRequestWrapper) {
			ContentCachingRequestWrapper wrapper = (ContentCachingRequestWrapper) request;
			paramStr = StringUtils.toEncodedString(wrapper.getContentAsByteArray(), Charset.forName(wrapper.getCharacterEncoding()));
		}
		// 记录开始时间
		long start = System.currentTimeMillis();

		log.info("请求| ip:{} | 请求接口:{}|请求发生异常|全局捕捉|请求时间 :{}|  参数:{} ", ip, requestURL,LocalDateTime.now(), paramStr);
		// 执行目标方法
		result = pjp.proceed();

		return result;
	}
	//</editor-fold>

	//<editor-fold desc="访问切入点">
	@Pointcut("execution(public * com.abcode.st.controller.*..*(..))")
	public void privilege() {
	}

	@Around("privilege()")
	public Object around(ProceedingJoinPoint pjp) throws Throwable {

		// 获取类名
		String className = pjp.getTarget().getClass().getName();// pjp.getTarget().getClass().getSimpleName();
		// 获取执行的方法名称
		String methodName = pjp.getSignature().getName();
		// 获取参数名称
		String[] parameterNamesArgs = ((MethodSignature) pjp.getSignature()).getParameterNames();
		// 定义返回参数
		Object result = null;
		// 获取方法参数
		Object[] args = pjp.getArgs();
		//HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
		RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
		if(ObjectUtils.isEmpty(requestAttributes)){
			return null;
		}
		HttpServletRequest request = ((ServletRequestAttributes) requestAttributes).getRequest();
		// 请求的URL
		String requestURL = request.getRequestURL().toString();
		String ip = getIpAddr(request);
//      这里是是为了捕获文件上传时的异常
		StringBuffer paramsBuf = new StringBuffer();
		try {
			StandardMultipartHttpServletRequest standardMultipartHttpServletRequest = new StandardMultipartHttpServletRequest(request);
			Iterator it = standardMultipartHttpServletRequest.getFileNames();
			if(it.hasNext()){
				return  pjp.proceed();
			}
		}catch (MultipartException e){
//			log.info("---> 没有问题 ");
		}
		// 获取请求参数集合并进行遍历拼接
		for (int i = 0; i < args.length; i++) {
			if (paramsBuf.length() > 0) {
				paramsBuf.append("|");
			}
			// 自定义的对象参数，进行属性值细化拼接显示
			if (args[i] instanceof HttpServletRequest || args[i] instanceof HttpServletResponse || args[i] instanceof BindingResult) {
				paramsBuf.append(parameterNamesArgs[i]).append(" = ").append(args[i]);
			} else {
				paramsBuf.append(parameterNamesArgs[i]).append(" = ").append(JSONObject.toJSONString(args[i]));
			}
		}

		StringBuffer headerBuf = new StringBuffer();
		Enumeration<String> headerNames = request.getHeaderNames();
		while (headerNames.hasMoreElements()) {
			String key = headerNames.nextElement();
			String value = request.getHeader(key);
			if (headerBuf.length() > 0) {
				headerBuf.append("|");
			}
			headerBuf.append(key).append("=").append(value);
		}
		// 记录开始时间
		LocalDateTime start = LocalDateTime.now();

		log.info("请求| ip:{} | 请求接口:{} | 方法 :{} | 参数:{} |请求时间 :{}", ip, requestURL, methodName, paramsBuf.toString(), start);
		// 执行目标方法
		result = pjp.proceed();
		//日志返回结果显示
		String resultStr = "";
		try {
			resultStr =	JSON.toJSONString(result);
		} catch (Exception e) {
			log.error("请求| ip:{} | 请求接口:{} |返回值JOSN化出现异常 ", ip, requestURL, e.getMessage());
		}
		int rstLength = resultStr.length();
		if(StringUtils.isNotBlank(resultStr) && rstLength > 2000){
			resultStr = "请求结果长度:"+ resultStr.length() +"，大于2000";
		}
		// 获取执行完的时间 打印返回报文
		long handleTime = Duration.between(start, LocalDateTime.now()).toMillis();
		if(handleTime > 10000l){
			//响应时间超过3秒
			log.info("返回| 请求接口:{}|接口响应时间超过10秒 | 返回|方法 :{} |  参数:{} | 处理时间:{} 毫秒 | 返回结果 :{}", requestURL, methodName, paramsBuf.toString(), handleTime, resultStr);
		}else if(handleTime > 6000l){
			//响应时间超过3秒
			log.info("返回| 请求接口:{}| 接口响应时间超过6秒 | 返回|方法 :{} | 参数:{} | 处理时间:{} 毫秒 | 返回结果 :{}", requestURL, methodName, paramsBuf.toString(), handleTime, resultStr);

		}else if(handleTime > 3000l){
			//响应时间超过3秒
			log.info("返回| 请求接口:{}| 接口响应时间超过3秒 | 返回|方法 :{} | 参数:{} | 处理时间:{} 毫秒 | 返回结果 :{}", requestURL, methodName, paramsBuf.toString(), handleTime, resultStr);
		}
		else{
			log.info("返回| 请求接口:{}| 返回|方法 :{}  | 参数:{} | 处理时间:{} 毫秒 | 返回结果 :{}", requestURL, methodName, paramsBuf.toString(), handleTime, resultStr);
		}
		return result;
	}
	//</editor-fold>

	/**
	 * @Description: 获取ip
	 * @param request
	 * @return String 返回类型
	 */
	public String getIpAddr(HttpServletRequest request) {
		String ipAddress;
		ipAddress = request.getHeader("x-forwarded-for");
		if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
			ipAddress = request.getHeader("Proxy-Client-IP");
		}
		if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
			ipAddress = request.getHeader("WL-Proxy-Client-IP");
		}
		if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
			ipAddress = request.getRemoteAddr();
		}
		// 对于通过多个代理的情况，第一个IP为客户端真实IP,多个IP按照','分割
		if (ipAddress != null && ipAddress.length() > 15) {
			if (ipAddress.indexOf(",") > 0) {
				ipAddress = ipAddress.substring(0, ipAddress.indexOf(","));
			}
		}
		// 或者这样也行,对于通过多个代理的情况，第一个IP为客户端真实IP,多个IP按照','分割
		//return ipAddress!=null&&!"".equals(ipAddress)?ipAddress.split(",")[0]:null;
		return ipAddress;
	}
}

